package com.alinesno.cloud.common.web.login.controller;

import java.io.IOException;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.ExcessiveAttemptsException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.util.WebUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import com.alinesno.cloud.common.web.base.controller.BaseController;
import com.alinesno.cloud.common.web.base.response.ResponseBean;
import com.alinesno.cloud.common.web.base.response.ResponseGenerator;
import com.alinesno.cloud.common.web.base.utils.ManagerSettingsUtils;
import com.alinesno.cloud.common.web.login.aop.AccountRecord;
import com.alinesno.cloud.common.web.login.aop.AccountRecord.RecordType;
import com.alinesno.cloud.common.web.login.constants.LoginConfigurationBean;
import com.alinesno.cloud.common.web.login.constants.LoginConstants;
import com.alinesno.cloud.common.web.login.token.LoginAccountToken;


/**
 * 控制层
 * @author LuoAnDong
 * @since 2018年11月27日 上午6:41:40
 */
@Controller
@Scope("prototype")
public class LoginController extends BaseController {

	private static final Logger log = LoggerFactory.getLogger(LoginController.class) ; 

	/**
	 * 进入用户登陆界面
	 * @throws IOException 
	 */
	@AccountRecord(value="进入登陆界面.",type = RecordType.LOGIN_GET)
	@GetMapping(value = "/login")
	public String login(HttpServletRequest request , Model model) throws IOException {
        Subject subject = SecurityUtils.getSubject();
        boolean isAuth = subject.isAuthenticated() ; 
        
        log.debug("isAuthenticated:{}" , isAuth);
        if(isAuth) {
           WebUtils.redirectToSavedRequest(request, response, DASHBAORD_PATH); 
           return null ; 
        }
        
        // 是否开启验证码
        boolean b = ManagerSettingsUtils.isOpenCaptcha() ; 
        if(b) { 
        	model.addAttribute("openCaptcha", true) ; 
        }
        
        return "login" ; 
	}

	/**
	 * 提交登陆信息
	 * @param user
	 * @param bindingResult
	 * @param redirectAttributes
	 * @return
	 */
	@AccountRecord(value="提交登陆信息.",type = RecordType.LOGIN_POST)
	@ResponseBody
    @PostMapping("/login")
    public ResponseBean login(@Valid LoginAccountToken account , BindingResult bindingResult, RedirectAttributes redirectAttributes) {
		String errorMessage = "" ; 
        if (bindingResult.hasErrors()) {
            return ResponseGenerator.genUnauthorizedResult() ; 
        }
        String username = account.getUsername();
        log.info("准备登陆用户 => {}", username);
        
        //获取当前的Subject
        Subject currentUser = SecurityUtils.getSubject();
        try {
            //在调用了login方法后,SecurityManager会收到AuthenticationToken,并将其发送给已配置的Realm执行必须的认证检查
            //每个Realm都能在必要时对提交的AuthenticationTokens作出反应
            //所以这一步在调用login(token)方法时,它会走到MyRealm.doGetAuthenticationInfo()方法中,具体验证方式详见此方法
            log.info("对用户[" + username + "]进行登录验证..验证开始");
            
            currentUser.login(account);
            
            log.info("对用户[" + username + "]进行登录验证..验证通过");
        } catch (UnknownAccountException uae) {
        	errorMessage = "对用户[" + username + "]进行登录验证..验证未通过,未知账户" ;
        	return ResponseGenerator.genFailMessage(errorMessage) ; 
        } catch (IncorrectCredentialsException ice) {
            errorMessage = "对用户[" + username + "]进行登录验证..验证未通过,错误的凭证";
            return ResponseGenerator.genFailMessage(errorMessage) ; 
        } catch (LockedAccountException lae) {
            errorMessage = "对用户[" + username + "]进行登录验证..验证未通过,账户已锁定";
            return ResponseGenerator.genFailMessage(errorMessage) ; 
        } catch (ExcessiveAttemptsException eae) {
            errorMessage = "对用户[" + username + "]进行登录验证..验证未通过,错误次数过多";
            return ResponseGenerator.genFailMessage(errorMessage) ;
        } catch (AuthenticationException ae) {
            //通过处理Shiro的运行时AuthenticationException就可以控制用户登录失败或密码错误时的情景
            errorMessage = "对用户[" + username + "]进行登录验证..验证未通过,堆栈轨迹如下";
            ae.printStackTrace();
            return ResponseGenerator.genFailMessage(errorMessage) ; 
        }
        //验证是否登录成功
        if (currentUser.isAuthenticated()) {
            log.info("用户[" + username + "]登录认证通过(这里可以进行一些认证通过后的一些系统参数初始化操作)");
          
            String successPath = LoginConfigurationBean.shiroLoginSuccessPath() ;
            if(successPath.startsWith("/")) {
            	successPath = successPath.substring(1, successPath.length()) ; 
            }
            
            log.debug("successPath:{}" , successPath);
            
            return ResponseGenerator.genSuccessResult(successPath) ; 
        } else {
        	account.clear();
            return ResponseGenerator.genUnauthorizedResult() ; 
        }
    }

    /**
     * 用户退出
     * @param redirectAttributes
     * @return
     */
	@AccountRecord(value="退出系统.",type=RecordType.LOGOUT)
    @GetMapping("/logout")
    public String logout(RedirectAttributes redirectAttributes , HttpServletRequest request) {
        //使用权限管理工具进行用户的退出，跳出登录，给出提示信息
		
		log.debug("自定义用户退出响应.");
    	
        SecurityUtils.getSubject().logout();
        request.removeAttribute(LoginConstants.CURRENT_USER);
        redirectAttributes.addFlashAttribute("message", "您已安全退出");

		return this.redirect(LoginConfigurationBean.shiroIndexPath()); 
    }


}
